#include "pch.h"
#include "EnclaveProvider.h"
#include "sgx.h"
#include "Vault_u.h"
#include "EnclaveWrap.h"

EnclaveProvider::EnclaveProvider()
	: enclave_id_(0)
{
}

EnclaveProvider::EnclaveProvider(sgx_enclave_id_t enclave_id)
	: enclave_id_(enclave_id)
{
}

EnclaveProvider::~EnclaveProvider()
{
}

int EnclaveProvider::createEnclave(const std::string &id)
{
    sgx_status_t sgx_ret = SGX_ERROR_UNEXPECTED;

    sgx_ret = sgx_create_enclave(name_.c_str(), SGX_DEBUG_FLAG, &launch_token_, &launch_token_updated_, &enclave_id_, NULL);
    if (sgx_ret != SGX_SUCCESS)
    {
        LOG(FATAL) << "cannot create enclave, error code = 0x" << std::hex << sgx_ret;
        return 1;
    }

    return initVault(enclave_id_, id.c_str());
}

void EnclaveProvider::destroyEnclave()
{
    uninitVault(enclave_id_);

    if (enclave_id_)
        sgx_destroy_enclave(enclave_id_);
}

int EnclaveProvider::initVault(sgx_enclave_id_t enclave_id, const std::string & id)
{
	id_ = id;

	int ret_val = 0;
	sgx_status_t sgx_ret = ::initVault(enclave_id, &ret_val, id.c_str());
	if (sgx_ret != SGX_SUCCESS || ret_val != 0)
	{
		LOG(ERROR) << "Init vault, error code = 0x" << std::hex << sgx_ret << ", retVal = 0x" << std::hex << ret_val;
		return 1;
	}

	return 0;
}

void EnclaveProvider::uninitVault(sgx_enclave_id_t enclave_id)
{
	int retVal = 0;
	::uninitVault(enclave_id, &retVal, id_.c_str());
}

int EnclaveProvider::encrypt_size(int buf_len)
{
	int retVal = 0;

	sgx_status_t sgx_ret = ::encrypt_size(enclave_id_, &retVal, id_.c_str(), buf_len);

	if (sgx_ret != SGX_SUCCESS)
	{
		LOG(ERROR) << "encrypt, error code = 0x" << std::hex << sgx_ret;
	}

	return retVal;
}

int EnclaveProvider::encrypt(const char * in_buf, int in_buf_len, char * out_buf, int out_buf_size)
{
    int retVal = 0;

	sgx_status_t sgx_ret = ::encrypt(enclave_id_, &retVal, id_.c_str(), in_buf, in_buf_len, out_buf, out_buf_size);

	if (sgx_ret != SGX_SUCCESS)
	{
		LOG(ERROR) << "encrypt, error code = 0x" << std::hex << sgx_ret;
	}

    return retVal;
}

int EnclaveProvider::encryptex(const char * in_buf, int in_buf_len, const int * value_lens, const int * value_types, int value_count, char * out_buf, int out_buf_size, int * out_value_lens)
{
	int retVal = 0;

	sgx_status_t sgx_ret = ::encryptex(enclave_id_, &retVal, id_.c_str(), in_buf, in_buf_len, value_lens, value_types, value_count, 
		out_buf, out_buf_size, out_value_lens);

	if (sgx_ret != SGX_SUCCESS)
	{
		LOG(ERROR) << "encryptex, error code = 0x" << std::hex << sgx_ret;
	}

	return retVal;
}

int EnclaveProvider::decrypt(const char * in_buf, int in_buf_len, char * out_buf, int out_buf_size)
{
    int retVal = 0;

	sgx_status_t sgx_ret = ::decrypt(enclave_id_, &retVal, id_.c_str(), in_buf, in_buf_len, out_buf, out_buf_size);

	if (sgx_ret != SGX_SUCCESS)
	{
		LOG(ERROR) << "decrypt, error code = 0x" << std::hex << sgx_ret;
	}

    return retVal;
}

int EnclaveProvider::public_key_encrypt(const char * in_buf, int in_buf_len, char * out_buf, int out_buf_size)
{
    int retVal = 0;

	sgx_status_t sgx_ret = ::public_key_encrypt(enclave_id_, &retVal, id_.c_str(), in_buf, in_buf_len, out_buf, out_buf_size);

	if (sgx_ret != SGX_SUCCESS)
	{
		LOG(ERROR) << "public_key_encrypt, error code = 0x" << std::hex << sgx_ret;
	}

    return retVal;
}

int EnclaveProvider::private_key_decrypt(const char * in_buf, int in_buf_len, char * out_buf, int out_buf_size)
{
    int retVal = 0;

	sgx_status_t sgx_ret = ::private_key_decrypt(enclave_id_, &retVal, id_.c_str(), in_buf, in_buf_len, out_buf, out_buf_size);

	if (sgx_ret != SGX_SUCCESS)
	{
		LOG(ERROR) << "private_key_decrypt, error code = 0x" << std::hex << sgx_ret;
	}

    return retVal;
}

int EnclaveProvider::private_key_encrypt(const char * in_buf, int in_buf_len, char * out_buf, int out_buf_size)
{
    int retVal = 0;

	sgx_status_t sgx_ret = ::private_key_encrypt(enclave_id_, &retVal, id_.c_str(), in_buf, in_buf_len, out_buf, out_buf_size);

	if (sgx_ret != SGX_SUCCESS)
	{
		LOG(ERROR) << "private_key_encrypt, error code = 0x" << std::hex << sgx_ret;
	}

    return retVal;
}

int EnclaveProvider::public_key_decrypt(const char * in_buf, int in_buf_len, char * out_buf, int out_buf_size)
{
    int retVal = 0;

	sgx_status_t sgx_ret = ::public_key_decrypt(enclave_id_, &retVal, id_.c_str(), in_buf, in_buf_len, out_buf, out_buf_size);

	if (sgx_ret != SGX_SUCCESS)
	{
		LOG(ERROR) << "public_key_decrypt, error code = 0x" << std::hex << sgx_ret;
	}

    return retVal;
}

int EnclaveProvider::sign(const char * in_buf, int in_buf_len, char * out_buf, int out_buf_size)
{
	int retVal = 0;
	sgx_status_t sgx_ret = ::sign(enclave_id_, &retVal, id_.c_str(), in_buf, in_buf_len, out_buf, out_buf_size);

	if (sgx_ret != SGX_SUCCESS)
	{
		LOG(ERROR) << "sign, error code = 0x" << std::hex << sgx_ret;
	}

	return retVal;
}

int EnclaveProvider::sha256_encrytp(const char * in_buf, int in_buf_len, char * out_buf, int out_buf_size)
{
	int retVal = 0;

	sgx_status_t sgx_ret = ::sha256_encrytp(enclave_id_, &retVal, id_.c_str(), in_buf, in_buf_len, out_buf, out_buf_size);

	if (sgx_ret != SGX_SUCCESS)
	{
		LOG(ERROR) << "sha256, error code = 0x" << std::hex << sgx_ret;
	}

	return retVal;
}

bool EnclaveProvider::crypto_key(std::string & key)
{
	int retVal = 0;

	char key_buf[256] = { 0 };

	sgx_status_t sgx_ret = ::crypto_key(enclave_id_, &retVal, id_.c_str(), key_buf, (int)sizeof(key_buf));

	if (sgx_ret != SGX_SUCCESS)
	{
		LOG(ERROR) << "sha256, error code = 0x" << std::hex << sgx_ret;
	}

	key = key_buf;

	return retVal;
}
